﻿using System;
using System.Collections.Generic;
using System.Linq;
using HHPS.CreditEducation.DataProvider;
using HHPS.CreditEducation.Frameworks.Commons;
using HHPS.CreditEducation.Frameworks.Constants;

namespace HHPS.CreditEducation.Business
{
    public partial class Business
    {
        #region Common

        private static bool StudyPlanCommonValidator(StudyPlan plan, out string message)
        {
            if (string.IsNullOrEmpty(plan.Name))
            {
                message = string.Format(ConstantMessages.RequireFieldIsBlank, "tiêu đề cho Kế hoạch học tập");
                return false;
            }
            if (plan.Name.Trim().Length > 15)
            {
                message = string.Format(ConstantMessages.FieldDataOverMaxLength, "Kế hoạch học tập", 15);
                return false;
            }
            if (string.IsNullOrEmpty(plan.Detail))
            {
                message = string.Format(ConstantMessages.RequireFieldIsBlank, "mô tả");
                return false;
            }
            if (plan.Name.Trim().Length > 100)
            {
                message = string.Format(ConstantMessages.FieldDataOverMaxLength, "Mô tả", 100);
                return false;
            }

            message = string.Empty;
            return true;
        }

        #endregion

        #region Add Study Plan

        public bool AddNewStudyPlanValidate(StudyPlan plan, out string message)
        {
            if (!StudyPlanCommonValidator(plan, out message)) return false;

            if (DataContex.StudyPlans.Any(s => s.Name.ToLower() == plan.Name.ToLower()))
            {
                message = string.Format(ConstantMessages.ItemIsExisted, "Kế hoạch học tập");
                return false;
            }
            //Maybe it will not validate start date
            return true;
        }

        public void AddNewStudyPlan(StudyPlan plan)
        {
            DataContex.StudyPlans.AddObject(plan);
            DataContex.SaveChanges();
        }

        #endregion

        #region Update Study Plan

        public bool EditStudyPlanValidator(StudyPlan studyPlan, out string message)
        {
            int id = studyPlan.Id;
            if (!DataContex.StudyPlans.Any(f => f.Id == id))
            {
                message = ConstantMessages.CanNotIdentifyItem;
                return false;
            }

            if (!StudyPlanCommonValidator(studyPlan, out message)) return false;

            if (DataContex.StudyPlans.Any(f => f.Name.ToLower() == studyPlan.Name.ToLower() && f.Id != id))
            {
                message = string.Format(ConstantMessages.ItemIsExisted, studyPlan.Name);
                return false;
            }

            return true;
        }

        public bool EditStudyPlan(StudyPlan studyPlan)
        {
            int id = studyPlan.Id;
            StudyPlan updateFaculty = DataContex.StudyPlans.SingleOrDefault(f => f.Id == id);

            if (updateFaculty == null)
                return false;

            //Utils.UpdateProperties(studyPlan, ref updateFaculty, new[] { (string)studyPlan.Properties.Id });
            updateFaculty.Name = studyPlan.Name;
            updateFaculty.Detail = studyPlan.Detail;
            updateFaculty.StartDate = studyPlan.StartDate;
            //updateFaculty.IdMajor = studyPlan.IdMajor;
            DataContex.SaveChanges();
            return true;
        }

        #endregion

        #region Delete Study Plan

        public bool DeleteStudyPlansValidator(List<StudyPlan> studyPlans, out string message)
        {
            const string intialize = "Kế hoạch: ";
            string itemsCannotIdentify = intialize;
            foreach (StudyPlan studyPlan in studyPlans)
            {
                int id = studyPlan.Id;
                if (!DataContex.StudyPlans.Any(f => f.Id == id))
                    itemsCannotIdentify += studyPlan.Name + ", ";
            }

            if (itemsCannotIdentify != intialize)
            {
                message = string.Format(ConstantMessages.SomeItemsCanNotIdentify, itemsCannotIdentify.TrimEnd(','));
                return false;
            }

            message = string.Empty;
            return true;
        }

        public void DeleteStudyPlans(List<StudyPlan> studyPlans)
        {
            for (int i = studyPlans.Count - 1; i >= 0; i--)
            {
                int id = studyPlans[i].Id;
                StudyPlan deleteItem = DataContex.StudyPlans.Single(f => f.Id == id);
                if (deleteItem.StudyCourses != null)
                {
                    for (int j = deleteItem.StudyCourses.Count - 1; j >= 0; j--)
                    {
                        if (deleteItem.StudyCourses.ToList()[j].StudyCourseDetails != null)
                        {
                            for (int k = deleteItem.StudyCourses.ToList()[j].StudyCourseDetails.Count - 1; k >= 0; k--)
                            {
                                DataContex.StudyCourseDetails.DeleteObject(deleteItem.StudyCourses.ToList()[j].StudyCourseDetails.ToList()[k]);
                            }
                        }
                        DataContex.StudyCourses.DeleteObject(deleteItem.StudyCourses.ToList()[j]);
                    }
                }

                DataContex.StudyPlans.DeleteObject(deleteItem);
            }
            DataContex.SaveChanges();
        }

        #endregion

        #region Study Course

        public Course GetCourseNotExistInStudyPlan(int studyPlanId)
        {
            var existCourses = DataContex.StudyPlans.First(s => s.Id == studyPlanId).StudyCourses.Select(c => c.IdCourse);
            return DataContex.Courses.FirstOrDefault(s => !existCourses.Contains(s.Id));
        }

        public IEnumerable<StudyCourse> GetStudyCourseInStudyPlan(int studyPlanId)
        {
            return DataContex.StudyPlans.First(s => s.Id == studyPlanId).StudyCourses;
        }

        public void AddNewStudyCourse(StudyCourse studyCourse)
        {
            DataContex.StudyCourses.AddObject(studyCourse);
            DataContex.SaveChanges();
        }

        /// <summary>
        /// Delete object
        /// </summary>
        public void DeleteStudyCourses(List<StudyCourse> studyCourses)
        {
            for (var i = studyCourses.Count - 1; i >= 0; i--)
            {
                var id = studyCourses[i].Id;
                var deleteItem = DataContex.StudyCourses.Single(f => f.Id == id);
                //Delete impact
                if (deleteItem.StudyCourseDetails != null)
                {
                    for (int j = deleteItem.StudyCourseDetails.Count - 1; j >= 0; j--)
                    {
                        DataContex.StudyCourseDetails.DeleteObject(deleteItem.StudyCourseDetails.ToList()[j]);
                    }
                }
                DataContex.StudyCourses.DeleteObject(deleteItem);
            }
            DataContex.SaveChanges();
        }

        public void SaveStudyCourse(StudyCourse studyCourse)
        {
            int id = studyCourse.Id;
            var updateStudyCourse = DataContex.StudyCourses.SingleOrDefault(f => f.Id == id);

            if (updateStudyCourse == null)
                return;

            //Utils.UpdateProperties(studyCourse, ref updateStudyCourse, new[] { (string)studyCourse.Properties.Id });
            updateStudyCourse.StartDate = studyCourse.StartDate;
            updateStudyCourse.IsComplete = studyCourse.IsComplete;

            DataContex.SaveChanges();
        }

        #endregion

        #region Study Course Detail

        public IEnumerable<StudyCourseDetail> GetStudyCourseDetailByStudyCourse(int studyCourseId)
        {
            return DataContex.StudyCourseDetails.Where(d => d.IdStudyCourse == studyCourseId);
        }

        public void DeleteStudyCourseDetails(List<StudyCourseDetail> studyCourseDetails)
        {
            for (var i = studyCourseDetails.Count - 1; i >= 0; i--)
            {
                var id = studyCourseDetails[i].Id;
                var deleteItem = DataContex.StudyCourseDetails.Single(f => f.Id == id);
                DataContex.StudyCourseDetails.DeleteObject(deleteItem);
            }
            DataContex.SaveChanges();
        }

        public void AddNewStudyCourseDetail(List<StudyCourseDetail> studyCourseDetails)
        {
            foreach (var courseDetail in studyCourseDetails)
            {
                DataContex.StudyCourseDetails.AddObject(courseDetail);
            }
            DataContex.SaveChanges();
        }

        #endregion

        #region Load Subject

        public List<Subject> LoadSubjectByStudyCourse(StudyCourse studyCourse)
        {
            //Danh sách các môn chưa học và đủ điều kiện lựa chọn, mức độ ưu tiên xếp theo thứ tự từ trên xuống
            //* Các điều kiện tạo sàng lọc
            // - Môn chưa được học (hoặc học chưa đạt) và chưa được chọn trong kỳ này
            // - Môn không bị phụ thuộc vào môn chưa học
            // - Sắp xếp theo thứ tự nhập (của loại môn học và môn học)

            var studyPlan = DataContex.StudyPlans.FirstOrDefault(p => p.Id == studyCourse.IdStudyPlan);
            if (studyPlan != null && studyPlan.StudyCourses != null)
            {
                var listSelectedSubject = (from course in studyPlan.StudyCourses.Where(sc => sc.StudyCourseDetails != null)
                                           from studyCourseDetail in course.StudyCourseDetails.Where(scd => scd.Subject != null)
                                           select studyCourseDetail.Subject).Select(s => s.Id).ToList();

                var listSubject = DataContex.Subjects.Where(s => !listSelectedSubject.Contains(s.Id)).ToList();

                if (listSubject.Count() < 1) return new List<Subject>();

                var listSubjectHasRequireId = DataContex.SubjectRequires.Select(s => s.IdSubject);
                var listSubjectId = listSubject.Select(s => s.Id);

                return (from subject in listSubject
                        let subjectId = subject.Id
                        where !listSubjectHasRequireId.Contains(subjectId) || (listSubjectHasRequireId.Contains(subjectId) && !DataContex.SubjectRequires.Where(sr => sr.IdSubject == subjectId).Any(su => listSubjectId.Contains(su.IdSubjectRequire)))
                        select subject).ToList();
            }

            return new List<Subject>();
        }

        #endregion

        public bool AllStudyCourseIsComplete(StudyPlan studyPlan)
        {
            return !DataContex.StudyCourses.Where(c => c.IdStudyPlan == studyPlan.Id).Any(c => !c.IsComplete);
        }
    }
}